/*================================================================
 *   Copyright (C) 2022 Sangfor Ltd. All rights reserved.
 *   
 *   文件名称：oj_tools.hpp
 *   创 建 者：wudu
 *   创建日期：2022年04月25日
 *   描    述：
 *
 ================================================================*/

#pragma once
#include <sys/time.h>
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <unordered_map>

#include <boost/algorithm/string.hpp>

using namespace std;

class StringUtil{
    public:
        /*
         *  boost::split()
         *      第一个参数：切割完成之后的内容（vector）
         *      第二个参数：要切割什么内容
         *      第三个参数：按照什么分割符进行切割
         *      第四个参数: 多个分割符是否进行压缩
         * */
        static void Spilt(const string& input, const string& spilt_char, vector<string>* output){
            boost::split(*output, input, boost::is_any_of(spilt_char), boost::token_compress_off);
        }
};


class FileUtil{
    public:
        static bool ReadFile(const string& filename, string* content){
            ifstream file(filename.c_str());
            if(!file.is_open()){
                perror("open");
                return false;
            }

            string line;
            while(getline(file, line)){
                *content += line + "\n";
            }

            file.close();
            return true;
        }

        //写文件
        static bool WriteFile(const string& filename, const string& data){
            ofstream file(filename.c_str());
            if(!file.is_open()){
                return false;
            }
            file.write(data.c_str(), data.size());
            file.close();
            return true;
        }
};

class UrlUtil{
    public:
        static void PraseBody(const string& body, unordered_map<string, string>* body_kv){
            vector<string> vec;
            StringUtil::Spilt(body, "&", &vec);

            //vec[0]: code=xxx
            //vec[1]: stdin=xxx
            for(const auto& kv : vec){
                vector<string> v;
                StringUtil::Spilt(kv, "=", &v);

                //v[0] : code
                //v[1] : xxx
                if(v.size() != 2){
                    continue;
                }

                //需要针对v[1]进行url解码
                (*body_kv)[v[0]] = UrlDecode(v[1]);
            }
        }


        static unsigned char ToHex(unsigned char x) 
        { 
            return  x > 9 ? x + 55 : x + 48; 
        }

        static unsigned char FromHex(unsigned char x) 
        { 
            unsigned char y;
            if (x >= 'A' && x <= 'Z') y = x - 'A' + 10;
            else if (x >= 'a' && x <= 'z') y = x - 'a' + 10;
            else if (x >= '0' && x <= '9') y = x - '0';
            else assert(0);
            return y;
        }

        static std::string UrlEncode(const std::string& str)
        {
            std::string strTemp = "";
            size_t length = str.length();
            for (size_t i = 0; i < length; i++)
            {
                if (isalnum((unsigned char)str[i]) || 
                        (str[i] == '-') ||
                        (str[i] == '_') || 
                        (str[i] == '.') || 
                        (str[i] == '~'))
                    strTemp += str[i];
                else if (str[i] == ' ')
                    strTemp += "+";
                else
                {
                    strTemp += '%';
                    strTemp += ToHex((unsigned char)str[i] >> 4);
                    strTemp += ToHex((unsigned char)str[i] % 16);
                }
            }
            return strTemp;
        }

        static std::string UrlDecode(const std::string& str)
        {
            std::string strTemp = "";
            size_t length = str.length();
            for (size_t i = 0; i < length; i++)
            {
                if (str[i] == '+') strTemp += ' ';
                else if (str[i] == '%')
                {
                    assert(i + 2 < length);
                    unsigned char high = FromHex((unsigned char)str[++i]);
                    unsigned char low = FromHex((unsigned char)str[++i]);
                    strTemp += high*16 + low;
                }
                else strTemp += str[i];
            }
            return strTemp;
        }
};



class TimeUtil{
    public:
        static int64_t GetTimeStmap(){
            struct timeval tv;
            gettimeofday(&tv, NULL);
            return tv.tv_sec * 1000 + tv.tv_usec / 1000;
        }
};


